
算术表达式是每一种编程语言的一部分。下面是一个算术表达式计算语言calc的例子，calc表达式会编译成一个计算以下表达式的应用程序:

\begin{shell}
with a, b: a * (4 + b)
\end{shell}

表达式中使用的变量必须用关键字with声明。该程序会编译成一个应用程序，该程序向用户询问a和b变量的值，并输出结果。

示例总是简单并容易理解的，但作为编译器作者，需要比这更全面的实现和测试规范。首先，编程语言的载体是语法。

\mySubsubsection{2.2.1.}{描述程序设计语言语法的形式}

语言中的元素，例如关键字、标识符、字符串、数字和操作符，称为标记(token)。从这个意义上说，程序是一个标记序列，语法指定了哪些序列是有效的。

通常，语法以扩展的Backus-Naur形式(EBNF)编写。语法规则有左边和右边，左边只有一个符号，叫做非终结符；右侧由非终结符、记号和用于替代和重复的元符号组成。来看看calc语言的语法:

\begin{shell}
calc : ("with" ident ("," ident)* ":")? expr ;
expr : term (( "+" | "-" ) term)* ;
term : factor (( "*" | "/") factor)* ;
factor : ident | number | "(" expr ")" ;
ident : ([a-zAZ])+ ;
number : ([0-9])+ ;
\end{shell}

第一行中，calc是非终结符。若没有特别说明，则语法的第一个非终结符是开始符号。冒号(:)是规则左右两边之间的分隔符，"with"、","和":"是表示这个字符串的标记，括号用于分组。组可以是可选的，也可以是重复的。右括号后的问号(?)表示一个可选的组。星号*表示零次或多次重复，加号+表示一次或多次重复。ident和expr是非终结符，处理它们使用的是另一种规则。分号(;)表示规则的结束，第二行中的管道|表示另一种选择。最后，最后两行的括号[]表示字符类。有效字符写在括号内。例如，字符类[a-zA-Z]匹配一个大写或小写字母，而([a-zA-Z])+匹配这些字母中的一个或多个。看上去，这就是一个正则表达式。

\mySubsubsection{2.2.2.}{语法如何帮助编译器作者?}

这样的语法看起来像一个玩具，但对编译器作者很有意义。首先，定义所有标记，这是创建词法分析器所需的，语法规则可以转化为解析器。若有解析器是否正确工作的问题，则语法就可以作为标准进行衡量。

然而，语法并不能定义编程语言的所有方面。语法的含义——语义——也必须定义。为此目的的形式也开发出来了，因为是在最初引入该语言时拟定的，所以通常在纯文本中指定。

了解了这些知识，接下来的两节将介绍词法分析如何将输入转换为标记序列，以及语法如何使用C++进行语法分析。